package com.zte.claa.inficombo.csa.app.service.modbus.impl;

import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.zte.claa.inficombo.csa.app.model.redis.DevMeteData;
import com.zte.claa.inficombo.csa.app.service.modbus.ModbusMsgParser;
import com.zte.claa.inficombo.csa.app.service.modbus.entity.ModbusMsgWapper;
import com.zte.claa.inficombo.csa.app.service.modbus.entity.ModbusRequestConfig;
import com.zte.claa.inficombo.csa.app.service.modbus.entity.ModbusResponseRelConfig;
import com.zte.claa.inficombo.csa.app.util.NumUtils;


public class ModbusMsgParserImpl implements ModbusMsgParser{

	// 日志打印.
	private Logger logger = LoggerFactory.getLogger(ModbusMsgParserImpl.class);	
	
	private List<ModbusResponseRelConfig> modbusResponseRelList;
	
	//保持寄存器的功能码
	private final static Integer FUNC_3 = 3;
			
	public ModbusMsgParserImpl(List<ModbusResponseRelConfig> modbusResponseRelList){
		this.modbusResponseRelList = modbusResponseRelList;
	}
		
	
	public List<DevMeteData> parser(ModbusMsgWapper msg){	
		if(msg == null){
			return null;
		}
		ModbusRequestConfig requestConfig = msg.getRequestConfig();
		if(requestConfig == null){
			return null;
		}										
		if(FUNC_3.equals(requestConfig.getFunc())){
			return parserfunc_3(msg);
		}else{
			return null;
		}		
	}
	
		
	//解析03功能码保持寄存器中的数据
	protected List<DevMeteData> parserfunc_3(ModbusMsgWapper msg) {
		byte[] orgdata = msg.getMsg();
		
		if(orgdata == null || orgdata.length == 0){
			return null;
		}
		if(modbusResponseRelList == null || modbusResponseRelList.size() == 0){
			return null;
		}		
		ModbusRequestConfig requestConfig = msg.getRequestConfig();	
		//单个测点字节数
		int pointByteNum = requestConfig.getPointbytenum();
		//保持寄存器一个测点至少需要一个寄存器两个字节
		if(!(pointByteNum > 1)){
			return null;
		}
		//orgdata.length->响应中包含的字节数
		//pointByteNum->一个测点包含的字节数
		//pointNum->测点个数
		int pointNum = orgdata.length / pointByteNum;
		//简单校验,测点数与配置的逻辑资源数必须一一对应
		if(pointNum != modbusResponseRelList.size()){
			return null;
		}
		
		float[] values = new float[pointNum];
		
		try{					
			mapOrgData(orgdata, values, pointNum, pointByteNum, requestConfig.getByteorder());	
		}catch (Exception e) {
			logger.error("Parser modbus msg failed, orgData to poinData error:" + e.getMessage());
			return null;
		}

		List<DevMeteData> devMeteDataList = new ArrayList<>();
		//每个测点的比例系数
		float ratio = 1.0f;	
		for(ModbusResponseRelConfig config : modbusResponseRelList){
			try{				
				ratio = NumUtils.parseFloat(config.getRatio(),1.0f);			
				DevMeteData devMeteData = new DevMeteData();
				HashMap<String, Object> data = new HashMap<String, Object>();
				data.put(config.getTargetname(), values[config.getResindex()] * ratio);
				devMeteData.setDeveui(config.getResid());
				devMeteData.setProjectid(config.getProjectid());
				devMeteData.setMdata(data);
				devMeteDataList.add(devMeteData);
			}catch (Exception e) {
				logger.error("Parser modbus point failed, create DevMeteData object error" + e.getMessage());
				//这里要增加一个null,保证返回的链表长度与配置的测点数一致
				devMeteDataList.add(null);
				continue;
			}		
			logger.info("modbus msg rpt: " + devMeteDataList);		
		}
		return devMeteDataList;
	}
	
	
	//将原始寄存器数据映射成浮点数组
	/**
	 * @param orgdata 原始数据
	 * @param values 解析后的数据
	 * @param pointNum 解析的测点数
	 * @param pointRegisterNum 单测点需要的寄存器数
	 * @param byteorder 字节序 ,字节序,0:cdab,1:abcd,多个寄存器表示一个指标时,该参数有效
	 */
	protected void mapOrgData(byte[] orgdata, 
							  float[] values, 
							  int pointNum, 
							  int pointRegisterNum, 
							  int byteorder) throws Exception{	

		for(int i = 0; i < orgdata.length; i++){
			logger.info("Original data index: " + i + ", value : "+ Integer.toHexString(orgdata[i]));			
		}	
		byte[] temp = new byte[4];
		float result = 0.0f;
		//一个测点一个寄存器,直接拷贝
		if(pointRegisterNum == 1){
			for(int i = 0; i < orgdata.length; i++){
				values[i] = orgdata[i];
			}
		//一个测点4个寄存器(保持寄存器模拟量是4个byte的寄存器,但映射到modbus的image是两个16进制寄存器)
		}else if(pointRegisterNum == 4){
			for(int i = 0; i < pointNum; i++){
				temp[0] = orgdata[4 * i];
				temp[1] = orgdata[4 * i + 1];
				temp[2] = orgdata[4 * i + 2];
				temp[3] = orgdata[4 * i + 3];
				//字节重排序
				temp = reOrder(temp, byteorder);
				//计算结果
				result = getFloatFromByte(temp);
				values[i] = result;
			}			
		}else{
			//TODO
		}
		for(int i = 0; i < values.length; i++){
			logger.info("Parser data index: " + i + ", value : "+ values[i]);
		}
	}
	
	/**
	 * 4字节重排序
	40071  41c9 ba 
	40072  bcd3 dc
	byte[] bs = new byte[4];
	bs[1] = (byte) 201; //c9 a
	bs[0] = (byte) 65;	//41 b
	bs[3] = (byte) 211;	//d3 c
	bs[2] = (byte) 188;	//bc d		
	cdab		
	 * @param orgdata
	 * @param byteorder
	 * @return
	 * @throws Exception
	 */
	protected byte[] reOrder(byte[] orgdata, int byteorder)throws Exception{
		if(orgdata.length != 4){
			return null;
		}
		
		byte[] result = new byte[4];
			//cdab
			if(byteorder == 0){
				result[0] = orgdata[0];
				result[1] = orgdata[1];
				result[2] = orgdata[2];
				result[3] = orgdata[3];
			//cdab
			}else if(byteorder == 1){
				result[0] = orgdata[1];
				result[1] = orgdata[0];
				result[2] = orgdata[3];
				result[3] = orgdata[2];
			//abcd
			}else if(byteorder == 2){
				result[0] = orgdata[3];
				result[1] = orgdata[2];
				result[2] = orgdata[1];
				result[3] = orgdata[0];
			//abcd
			}else if(byteorder == 3){
				result[0] = orgdata[2];
				result[1] = orgdata[3];
				result[2] = orgdata[0];
				result[3] = orgdata[1];
			}else{
				//TODO
			}		
		return result;
	}
		
	//byte数组转float
	protected float getFloatFromByte(byte[] orgdata) throws Exception{
		if(orgdata == null || orgdata.length != 4){
			logger.error("GetFloatFromByte error: " + orgdata.toString());
			throw new Exception("GetFloatFromByte error.");
		}		
		return ByteBuffer.wrap(orgdata).getFloat();
	} 

	
}
